#include "StdAfx.h"
#include "CubeMesh.h"
#include "GraphicsController.h"
#include <d3d9.h>
#include <stdexcept>
#include <string>


///////////////////////////////////////////////////////////////////////////////

DWORD CCubeVertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL;

///////////////////////////////////////////////////////////////////////////////

CCubeMesh::CCubeMesh(CGraphicsController& graphicsController)
: m_d3Device(graphicsController.getD3Device()),
      m_vertexBuffer(NULL),
      m_indexBuffer(NULL),
      m_facesCount(0)
{
   m_vertexBuffer = graphicsController.createVertexBuffer(sizeof(CCubeVertex) * 24, D3DUSAGE_WRITEONLY, CCubeVertex::FVF, D3DPOOL_MANAGED);
   m_indexBuffer = graphicsController.createIndexBuffer(sizeof(USHORT) * 36, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED);

   CCubeVertex* pVertex = NULL;
   HRESULT res = m_vertexBuffer->Lock(0, 0, (void**)&pVertex, 0);
   if (FAILED(res) || (pVertex == NULL))
   {
      throw std::logic_error(
         std::string("Cannot lock the cube mesh's vertex buffer"));
   }

   USHORT* pIndex = NULL;
   res = m_indexBuffer->Lock(0, 0, (void**)&pIndex, 0);
   if (FAILED(res) || (pVertex == NULL))
   {
      throw std::logic_error(
         std::string("Cannot lock the cube mesh's index buffer"));
   }

   // back face
   *pVertex++ = CCubeVertex(-2, -2, -2, 0, 0, -1);
   *pVertex++ = CCubeVertex(-2,  2, -2, 0, 0, -1);
   *pVertex++ = CCubeVertex( 2,  2, -2, 0, 0, -1);
   *pVertex++ = CCubeVertex( 2, -2, -2, 0, 0, -1);
   *pIndex++ = 0; *pIndex++ = 1; *pIndex++ = 2;
   *pIndex++ = 0; *pIndex++ = 2; *pIndex++ = 3;

   // right face
   *pVertex++ = CCubeVertex( 2, -2, -2, 1, 0, 0);
   *pVertex++ = CCubeVertex( 2,  2, -2, 1, 0, 0);
   *pVertex++ = CCubeVertex( 2,  2,  2, 1, 0, 0);
   *pVertex++ = CCubeVertex( 2, -2,  2, 1, 0, 0);
   *pIndex++ = 4; *pIndex++ = 5; *pIndex++ = 6;
   *pIndex++ = 4; *pIndex++ = 6; *pIndex++ = 7;

   // front face
   *pVertex++ = CCubeVertex( 2, -2,  2, 0, 0, 1);
   *pVertex++ = CCubeVertex( 2,  2,  2, 0, 0, 1);
   *pVertex++ = CCubeVertex(-2,  2,  2, 0, 0, 1);
   *pVertex++ = CCubeVertex(-2, -2,  2, 0, 0, 1);
   *pIndex++ = 8; *pIndex++ = 9; *pIndex++ = 10;
   *pIndex++ = 8; *pIndex++ = 10; *pIndex++ = 11;
   
   // left face
   *pVertex++ = CCubeVertex(-2, -2,  2, -1, 0, 0);
   *pVertex++ = CCubeVertex(-2,  2,  2, -1, 0, 0);
   *pVertex++ = CCubeVertex(-2,  2, -2, -1, 0, 0);
   *pVertex++ = CCubeVertex(-2, -2, -2, -1, 0, 0);
   *pIndex++ = 12; *pIndex++ = 13; *pIndex++ = 14;
   *pIndex++ = 12; *pIndex++ = 14; *pIndex++ = 15;

   // top face
   *pVertex++ = CCubeVertex(-2, 2, -2, 0, 1, 0);
   *pVertex++ = CCubeVertex(-2, 2,  2, 0, 1, 0);
   *pVertex++ = CCubeVertex( 2, 2,  2, 0, 1, 0);
   *pVertex++ = CCubeVertex( 2, 2, -2, 0, 1, 0);
   *pIndex++ = 16; *pIndex++ = 17; *pIndex++ = 18;
   *pIndex++ = 16; *pIndex++ = 18; *pIndex++ = 19;

   // bottom face
   *pVertex++ = CCubeVertex(-2, -2,  2, 0, -1, 0);
   *pVertex++ = CCubeVertex(-2, -2, -2, 0, -1, 0);
   *pVertex++ = CCubeVertex( 2, -2, -2, 0, -1, 0);
   *pVertex++ = CCubeVertex( 2, -2,  2, 0, -1, 0);
   *pIndex++ = 20; *pIndex++ = 21; *pIndex++ = 22;
   *pIndex++ = 20; *pIndex++ = 22; *pIndex++ = 23;

   m_vertexBuffer->Unlock();
   m_indexBuffer->Unlock();

   m_facesCount = 12;

   // bounding box
   m_boundingBox.min = D3DXVECTOR3(-2, -2, -2);
   m_boundingBox.max = D3DXVECTOR3(2, 2, 2);
}

///////////////////////////////////////////////////////////////////////////////

CCubeMesh::~CCubeMesh(void)
{
   if (m_vertexBuffer != NULL)
   {
      m_vertexBuffer->Release();
      m_vertexBuffer = NULL;
   }

   if (m_indexBuffer != NULL)
   {
      m_indexBuffer->Release();
      m_indexBuffer = NULL;
   }

   m_facesCount = 0;
}

///////////////////////////////////////////////////////////////////////////////

void CCubeMesh::render()
{
   m_d3Device.SetFVF(CCubeVertex::FVF);

   if ((m_vertexBuffer != NULL) && (m_indexBuffer != NULL))
   {
      m_d3Device.SetStreamSource(0, m_vertexBuffer, 0, sizeof(CCubeVertex));
      m_d3Device.SetIndices(m_indexBuffer);

      m_d3Device.DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 24, 0, m_facesCount);
   }
}

///////////////////////////////////////////////////////////////////////////////
